<template>
  <div class="chat-container">
    <!-- 顶部标题 -->
    <div class="chat-header">
      <h1>{{ granary?.name }}</h1>
    </div>

    <!-- 聊天消息区域 -->
    <div class="chat-messages">
      <!-- Display messages -->
      <template v-if="messages && messages.length">
        <div v-for="(message, index) in messages" :key="index" class="message-wrapper">
          <div class="message user" v-if="message.askRecord">
            <div class="message-content">
              <div class="text">{{ message.askRecord.content }}</div>
            </div>
          </div>
          <div class="message system" v-if="message.answerRecord">
            <!-- <div class="avatar">
              <img src="@/assets/icon/granary.png" alt="AI" />
            </div> -->
            <div class="message-content">
              <!-- <div class="text">{{ message.answerRecord.content }}</div> -->
              <div class="text">
                <markdown-renderer v-if="message.answerRecord.content" :content="message.answerRecord.content" />
              </div>
            </div>
          </div>
        </div>
      </template>
      <template v-else>
        <div class="no-messages">没有消息</div>
      </template>
    </div>

    <!-- 底部输入区域 -->
    <div class="chat-input">
      <unified-input-bar
        :isBlocking="isBlocking"
        :isVoiceMode="false"
        :showRagMode="true"
        :artifacts="modelArtifacts"
        :selectedArtifact="selectedArtifact"
        @send="handleSend"
        @voice-result="handleVoiceResult"
        @toggle-mode="showVoiceInput = !showVoiceInput"
        @stop-all="handleStopAll"
        @select-artifact="handleSelectArtifact"
        @select-rag-mode="handleSelectRagMode"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import UnifiedInputBar from '@/components/UnifiedInputBar.vue'
import MarkdownRenderer from '@/components/MarkdownRenderer.vue'

import { P2PExchangeRecord,ExchangeReocrdUnit,Phase, RecordUnit,Exchange } from '@/types/proto/api/v1/exchange_service';
import { ref,nextTick,onMounted,computed,onUnmounted } from 'vue';
import { RagTest } from '@/api/granary';
import { WebSocketClient} from "@/utils/websocket";
import { InteractType, RagMode, ReactionType } from '@/types/proto/common/common';
import { RagTestRequest,RagTestResponse,GetGranaryRequest,Granary } from '@/types/proto/api/v1/granary_service';
import { useRouter,useRoute } from 'vue-router'
import { useUserStore } from '@/store/user'
import { ElMessage } from 'element-plus'
import { GetGranary } from '@/api/granary';
import { getWssUrl } from '@/config';
import {  DecodeExchange } from '@/api/knot';
import { LLMModel, ListLLMModelResponse } from '@/types/proto/api/v1/llm_service';
import { ListModels } from '@/api/llm';
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const granary = ref<Granary | null>(null)
const showVoiceInput = ref(true)

const wsSocket  = ref<WebSocketClient|null>(null);

const isBlocking = ref(false);  // 添加状态控制是否在阻塞中
const messages = ref<ExchangeReocrdUnit[]|null>([]);
const isPhaseEnd = ref(true)
const ragMode=ref ('')
const models = ref<LLMModel[]>([])
const selectedArtifact =ref<string>('')
const currentArtifact = ref<string>('')

const isRecallMode = ref(false);
const recallType = ref('');

const scrollToBottom = () => {
    nextTick(() => {
        const container = document.querySelector('.chat-messages');
        if (container) {
            container.scrollTop = container.scrollHeight;
        }
    });
};
const handleVoiceResult = (ask: string) => {
    console.info('voice input:', ask);
}

const modelArtifacts = computed(() => models.value.map(model => ({
    name: model.name || model.model,
    urn: model.urn
})))

const handleSelectArtifact = (urn: string) => {
  console.log('选择模型:', urn);
  selectedArtifact.value = urn
};

const handleSelectRagMode = (mode: string) => {
  console.log('选择的召回模式:', mode);
  ragMode.value = mode
};

const onSayMessage = (message: any) => {
    if (! messages.value) {
        return
    }
    if (messages.value.length === 0) return;
    console.log('onSayMessage:', message);
    try {
      const res = DecodeExchange(message);
      console.log('onSayMessage res:', res);
      let isAppend = true
      switch (res.phase) {
          case Phase.Close:
              isPhaseEnd.value = true
              console.log('WebSocket message received phase close');
              wsSocket.value?.close();
              wsSocket.value = null;
              break;
          case Phase.Begin:
              updateLastMessage(res.content, true, false);
              break
          case Phase.End:
              isPhaseEnd.value = true
              console.log('WebSocket message received phase end:',res);
              messages.value[messages.value.length - 1].answerId = res.answerId;
              updateLastMessage(res.content, true, true);
              isBlocking.value = false; 
              console.error('set isBlocking to false');
              break;
          case Phase.Continue:
              isPhaseEnd.value = false
              if (messages.value[messages.value.length - 1].phase === Phase.Begin) {
                isAppend = false
              }
              updateLastMessage(res.content, isAppend);
              break;
          default:
              let lastMessage = messages.value[messages.value.length - 1];
              lastMessage.askId = res.askId
              lastMessage.answerId = res.answerId
              isPhaseEnd.value = false
              console.log('WebSocket message received phase:', res.phase);
              updateLastMessage(res.content);
              break;
        }
        messages.value[messages.value.length - 1].phase = res.phase
    } catch(error) {
      console.error('on message failed:', error);
      return;
    }

    scrollToBottom(); 
    console.log('onSayMessage end');
}

const sendMessageViaWebSocket = (message: string, p: Phase = Phase.Continue, id: string = "") => {
    const chatMessage = Exchange.create({
      phase: p,
      content: message, 
      askId: id,
      mode: RagMode[ragMode.value as keyof typeof RagMode] || RagMode.RAG_MODE_UNSPECIFIED,
    });
    const encodedMessage = Exchange.encode(chatMessage).finish();
    if (wsSocket.value && wsSocket.value.status() === WebSocket.OPEN) {
        wsSocket.value.send(encodedMessage);
    }
};

const createWebSocketConnection = (tid: string) => {
    let u = getWssUrl();
    const wsUrl = `${u}/${tid}`;
    wsSocket.value = new WebSocketClient(wsUrl, {onMessage:onSayMessage});
    wsSocket.value.connect(() => {
            console.log('Connection is ready!');
            sendMessageViaWebSocket("", Phase.HELLO, tid)
    });
};

const ragTest = async (message: string) => {
    const request = {
      content: message,
      urn: granary.value?.urn,
      interactType: InteractType.CHAT,
      ragMode: RagMode.NAIVE,
      llmModel: selectedArtifact.value,
    } as RagTestRequest;

    console.log('prepare to RagTest:');
    RagTest(request).then((res:RagTestResponse) => {
        console.log('RagTest response:', res);
        createWebSocketConnection(res.tid);
    })

}

const updateLastMessage = (content: string, isAppend: boolean = false, isCompleted: boolean = false) => {
    if (! messages.value) {
        return
    }

    if (messages.value.length === 0) return;

    let record = messages.value[messages.value.length - 1].answerRecord
    if (! record) {
        record = {} as RecordUnit
        messages.value[messages.value.length - 1].answerRecord = record
    }
    // 更新消息显示
    if (isAppend) {
       record.content += content;
    } else {
        record.content  = content;
    }

    messages.value[messages.value.length - 1].answerRecord  = record
    scrollToBottom();
};

const handleSend  = async (message: string) => {
    console.log("send msg:", message)
    if (isBlocking.value) {
      console.error('isBlocking is true, return');
      return;
    }

    if (! messages.value) {
      messages.value = [];
    }

    let askunit = {
        content: message,
        createTime: new Date(),
    } as RecordUnit
    
    let exchange = {
        askRecord: askunit,
        answerRecord: {}
    } as ExchangeReocrdUnit;
    messages.value.push(exchange);
    
    // await nextTick();
    scrollToBottom();
    if (currentArtifact.value != selectedArtifact.value) {
      currentArtifact.value = selectedArtifact.value
      if (wsSocket.value && wsSocket.value.status() === WebSocket.OPEN) {
        wsSocket.value.close();
        wsSocket.value = null;
      }
    }
    
    isBlocking.value = true; 
    console.log('set isBlocking to true');
    if (wsSocket.value && wsSocket.value.status() === WebSocket.OPEN) {
      if (isPhaseEnd.value) {
        sendMessageViaWebSocket(message, Phase.HELLO);
      } else {
        sendMessageViaWebSocket(message);
      }
    } else {
      wsSocket.value = null;
      try {
        ragTest(message);
      } catch (error) {
        console.error('Failed to test granary:', error);
        updateLastMessage('抱歉，发生了一些错误。请稍后再试。');
      }
    }
};

const handleToggleMode = () => {
  // 处理切换模式逻辑
}

const handleStopAll = () => {
  // 处理停止所有操作逻辑
}

const loadModels = () => {
  console.log("chat doc load models")
  const pageToken = { limit: 1000, offset: 0 }
  const filter = `model_type == 'chat'`
  ListModels({ pageSize: 1000, pageToken, filter: filter }).then((res:ListLLMModelResponse)=>{
    models.value = res.models
  }).catch(error => {
      console.error('Failed to fetch news:', error)
  })
} 

const parseParamFromRoute = async () => {
  try {
      console.log("granary config parse param")
      const urn = route.query.granary
      let reload = true
      console.log("config granary urn:", urn)
      if (urn === null || urn === undefined) {
          granary.value = null
          reload = false
      } else if (granary.value != null) {
          if (granary.value.urn === urn) {
              console.log("granary config no need to reload")
              reload = false
          }
      }

      if (reload) {
          console.log("granary config reload for granary:", urn)
          let req = {urn:urn} as GetGranaryRequest
          let res = await GetGranary(req)
          granary.value = res
      }

      if (granary.value != null) {
        selectedArtifact.value = granary.value.llmModel
      }
      loadModels()
      userStore.granary = granary.value
  } catch (error) {
      console.error('Error parsing granary config from route:', error)
  }
}

onUnmounted(() => {
  console.log("say onUnmounted")
  if (wsSocket.value) {
    console.log("say onUnmounted close wsSocket")
    wsSocket.value.close()
    wsSocket.value = null
  }
  isBlocking.value = false
  isPhaseEnd.value = true
})

onMounted(() => {
  console.log("granary config on mounted")
  if (!userStore.token) {
    ElMessage.warning('请先登录')
    router.push('/signin')
    return
  }

  if (userStore.granary != null) {
    granary.value = userStore.granary
  }
  parseParamFromRoute().then(() => {
  })
})
</script>

<style lang="scss" scoped>
.chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #f5f7fa;
}

.chat-header {
  padding: 16px;
  background-color: #fff;
  border-bottom: 1px solid #eee;
  
  h1 {
    font-size: 16px;
    color: #333;
    text-align: center;
    margin: 0;
  }
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
}

.message {
    margin-bottom: 24px;

    &.system {
        display: flex;
        align-items: flex-start;
        
        .message-header {
            margin-right: 12px;
            
            .avatar {
                width: 3px;
                height: 3px;
                border-radius: 3px;
            }
        }

        .message-content {
            flex: 1;
            max-width: 600px;
            text-align: left;
            
            .text {
                background-color: #F7F7F8;
                border-radius: 12px;
                padding: 12px 16px;
                font-size: 14px;
                line-height: 1.6;
                color: #1C1C1E;
                // white-space: pre-wrap;
                // word-wrap: break-word;
            }
        }
    }

    &.user {
        display: flex;
        justify-content: flex-end;
        
        .message-content {
        max-width: 600px;
        
        .text {
            background-color: #4E89FD;
            color: #ffffff;
            border-radius: 12px;
            padding: 12px 16px;
            font-size: 14px;
            line-height: 1.6;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
        }
    }
}

.ai-message {
  .message-content {
    background-color: #fff;
    padding: 16px;
    border-radius: 12px;
    max-width: 80%;
    
    .message-text {
      color: #333;
      font-size: 14px;
      line-height: 1.5;
      
      p {
        margin: 0;
        &:not(:last-child) {
          margin-bottom: 8px;
        }
      }
    }
  }
}

.chat-input {
  margin-top: auto;
}
</style>
